/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.bluelinelabs.conductor.viewpager;

import ohos.aafwk.content.IntentParams;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.PageSliderProvider;

import com.bluelinelabs.conductor.conductor.Controller;
import com.bluelinelabs.conductor.conductor.Router;
import com.bluelinelabs.conductor.conductor.RouterTransaction;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * lipeiquan
 *
 * @since 2021-05-06
 */
public abstract class RouterPagerProvider extends PageSliderProvider {


    private static final String KEY_SAVED_PAGES = "RouterPagerAdapter.savedStates";
    private static final String KEY_TAGS_KEYS = "RouterPagerAdapter.tags.keys";
    private static final String KEY_TAGS_VALUES = "RouterPagerAdapter.tags.values";
    private static final String KEY_MAX_PAGES_TO_STATE_SAVE = "RouterPagerAdapter.maxPagesToStateSave";
    private static final String KEY_SAVE_PAGE_HISTORY = "RouterPagerAdapter.savedPageHistory";

    private final Controller host;
    private int maxPagesToStateSave = Integer.MAX_VALUE;
    private final Map<Integer, String> tags = new HashMap<>();
    private HashMap<Integer, IntentParams> savedPages = new HashMap<>();
    private final HashMap<Integer, Router> visibleRouters = new HashMap<>();
    private ArrayList<Integer> savedPageHistory = new ArrayList<>();
    private Router currentPrimaryRouter;

    public RouterPagerProvider(Controller host) {
        this.host = host;
    }

    public abstract void configureRouter(Router router, int position);


    public void setMaxPagesToStateSave(int maxPagesToStateSave) {
        if (maxPagesToStateSave < 0) {
            throw new IllegalArgumentException("Only positive integers may be passed for maxPagesToStateSave.");
        }

        this.maxPagesToStateSave = maxPagesToStateSave;

        ensurePagesSaved();
    }


    @Override
    public Object createPageInContainer(ComponentContainer container, int position) {
        container.setId((int) System.currentTimeMillis());
        final String name = makeRouterName(container.getId(), getItemId(position));

        // Ensure we don't try to restore state for a router with a different ID just because
        // the position was reused. Fixes https://gitee.com/chinasoft_ohos/Conductor
        if (tags.get(position) != null && !tags.get(position).equals(name)) {
            savedPages.remove(position);
        }

        Router router = host.getChildRouter(container, name);
        if (!router.hasRootController()) {
            IntentParams routerSavedState = savedPages.get(position);

            if (routerSavedState != null) {
                router.restoreInstanceState(routerSavedState);
                savedPages.remove(position);
                savedPageHistory.remove((Integer) position);
            }
        }

        router.rebindIfNeeded();
        configureRouter(router, position);

        if (router != currentPrimaryRouter) {
            for (RouterTransaction transaction : router.getBackstack()) {
                transaction.controller.setOptionsMenuHidden(true);
            }
        }

        tags.put(position, name);
        visibleRouters.put(position, router);
        return router;
    }

    @Override
    public void destroyPageFromContainer(ComponentContainer container, int position, Object object) {

        Router router = (Router) object;

        IntentParams savedState = new IntentParams();
        router.saveInstanceState(savedState);
        savedPages.put(position, savedState);

        savedPageHistory.remove((Integer) position);
        savedPageHistory.add(position);

        ensurePagesSaved();

        host.removeChildRouter(router);

        visibleRouters.remove(position);

    }

    @Override
    public boolean isPageMatchToObject(Component view, Object object) {
        Router router = (Router) object;
        final List<RouterTransaction> backstack = router.getBackstack();
        for (RouterTransaction transaction : backstack) {
            if (transaction.controller.getView() == view) {
                return true;
            }
        }
        return false;
    }

    public Router getRouter(int position) {
        return visibleRouters.get(position);
    }

    public long getItemId(int position) {
        return position;
    }

    HashMap<Integer, IntentParams> getSavedPages() {
        return savedPages;
    }

    private void ensurePagesSaved() {
        while (savedPages.size() > maxPagesToStateSave) {
            int positionToRemove = savedPageHistory.remove(0);
            savedPages.remove(positionToRemove);
        }
    }

    private static String makeRouterName(int viewId, long id) {
        return viewId + ":" + id;
    }
}
